/*
 * @filename QueryService.java
 * @author barry
 * @version 0.0.1
 * @date 2020年3月6日
 */
package com.bnzj.core.persistence.query;

import java.util.List;
import java.util.Map;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.persistence.Tuple;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

/**
 * @author barry
 * @date 2020-03-06
 */
@Service
public class QueryService {
    
    @PersistenceContext
    private EntityManager entityManager;
    
    public int getCounts(QueryHelpBean bean) {
        if(!bean.isGenerated()) {
            bean.generate();
        }
        Query countQuery = createNativeQuery(bean.getBuildCountSQL(), bean.getParamsMap());
        return ((Number)countQuery.getSingleResult()).intValue();
    }

    public <T> Page<T> findAll(QueryHelpBean bean) {
        if(!bean.isGenerated()) {
            bean.generate();
        }
        int total = getCounts(bean);
        List<T> list = findList(bean, bean.getQuerySQL());
        return new PageImpl<T>(list, bean.getPageable(), total);
    }
    
    public <T> List<T> exportAll(QueryHelpBean bean) {
        if(!bean.isGenerated()) {
            bean.generate();
        }
        return findList(bean, bean.getExportSQL());
    }
    
    @SuppressWarnings("unchecked")
    public <T> List<T> findList(QueryHelpBean bean, String sql) {
        Query query = null;
        List<T> list = null;
        if(!StringUtils.isEmpty(bean.getResultSetMapping())) {
            query = createNativeQuery(sql, bean.getResultSetMapping(), bean.getParamsMap());
            list = query.getResultList();
        }else if(bean.getMappingClass() != null) {
            if(bean.isMappingClassIsEntity()) {
                query = createNativeQuery(sql, bean.getMappingClass(), bean.getParamsMap());
                list = query.getResultList();
            }else {
                query = createNativeQuery(sql, Tuple.class, bean.getParamsMap());
                list = QueryResultsConversionTool.tupleToBean(query.getResultList(), bean.getMappingClass());
            }
        } else {
            query = createNativeQuery(sql, Tuple.class, bean.getParamsMap());
            list = QueryResultsConversionTool.tupleToMap(query.getResultList());
        }
        return list;
    }

    public Query createNativeQuery(String sql, String resultSetMapping, Map<String, Object> parameterMap) {
        Query query = createNativeQuery(sql, resultSetMapping);
        if(parameterMap != null) {
            parameterMap.forEach((key, value) -> query.setParameter(key, value));
        }
        return query;
    }

    public Query createNativeQuery(String sql, Class<?> entityClass, Map<String, Object> parameterMap) {
        Query query = createNativeQuery(sql, entityClass);
        if(parameterMap != null) {
            parameterMap.forEach((key, value) -> query.setParameter(key, value));
        }
        return query;
    }

    public Query createNativeQuery(String sql, Class<?> resultClass) {
        return entityManager.createNativeQuery(sql, resultClass);
    }

    public Query createNativeQuery(String sql, String resultSetMapping) {
        return entityManager.createNativeQuery(sql, resultSetMapping);
    }

    public Query createNativeQuery(String sql, Map<String, Object> parameterMap) {
        Query query = entityManager.createNativeQuery(sql);
        if(parameterMap != null) {
            parameterMap.forEach((key, value) -> query.setParameter(key, value));
        }
        return query;
    }
}
